package message

import (
	"fmt"
	"ginchat/internal/globals"
	"ginchat/utils/logger"
	"os"
	"runtime"
	"sync"

	"github.com/smallnest/chanx"
	"go.uber.org/zap"
)

type message struct {
	Context any
	Type    string
}

type handler func(args ...any)

var (
	outputChan    *chanx.UnboundedChan[message]
	msgHandlerMap map[string]handler
	rwMutex       sync.RWMutex
	msgMapOnce    sync.Once
)

func InitMessage() {
	rwMutex.Lock()
	defer globals.GetWaitGroup().Done()
	outputChan = chanx.NewUnboundedChan[message](10)
	initMsgHandler()
	rwMutex.Unlock()

	for msg := range outputChan.Out {
		go func(m message) {
			defer func() {
				if err := recover(); err != nil {
					PrintRecover(err)
				}
			}()

			msgHandlerMap[m.Type](m.Context)
		}(msg)
	}

	os.Exit(1)
}

func addMessageHandler(msgType string, f handler) {
	msgMapOnce.Do(func() {
		msgHandlerMap = make(map[string]handler)
	})
	msgHandlerMap[msgType] = f
}

func initMsgHandler() {
	addMessageHandler("info", func(args ...any) {
		var log = logger.GetCMDLogger()
		log.Info(fmt.Sprint(args...))
	})

	addMessageHandler("error", func(args ...any) {
		var log = logger.GetCMDLogger()
		log.Error(fmt.Sprint(args...))
	})

	addMessageHandler("warn", func(args ...any) {
		var log = logger.GetCMDLogger()
		log.Warn(fmt.Sprint(args...))
	})

	addMessageHandler("exit", func(args ...any) {
		var log = logger.GetCMDLogger()
		rwMutex.Lock()
		log.Fatal("service stopping...", zap.String("error", fmt.Sprint(args...)))
		close(outputChan.In)
	})

	addMessageHandler("recover", func(errs ...any) {
		for _, err := range errs {
			switch err.(type) {
			case runtime.Error:
				PrintErr("runtime error:", err)
			default:
				PrintErr("error: ", err)
			}
		}
	})
}
